﻿using System;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;


public class PlayerEntity : MovableEntity
{
    public Animator animator;
    
    public PlayerEntityData entityData;
    
    public bool isMoved;
    public bool isPlayerDeckDisplayed;
    public bool isSelectableTileDisplayed;

    private int attackStep = 0;
    private PlayerProxier _playerProxier;
    
    public GameObject _hpBar;
    public TextMeshProUGUI _hpCountText;
    public Image _shieldImage;
    public TextMeshProUGUI _shieldCountText;
    public DisplayDamageNumber damageDrawer;
    
    private LifeBlock[] _currentHpBlock;
    

    private SpriteRenderer m_spriteRenderer;

    private static readonly int SlashStep = Animator.StringToHash("slashStep");
    private static readonly int ShootStep = Animator.StringToHash("shootStep");

    private static readonly int Cover = Animator.StringToHash("cover");
    private static readonly int Battle = Animator.StringToHash("battle");
    
    private static readonly int SlashOrShootAttack = Animator.StringToHash("slashOrShoot");

    private GameSession _gameSession;

    public override void FlushStatus()
    {
        _gameSession.FlushHpBar(_hp, _hp_max, _hpBar);
        _gameSession.FlushHpText(_hpCountText, _hp);
        _gameSession.FlushShieldText(_shieldCountText, _shieldImage, _shield);
    }
    
    private void Awake()
    {
        currentCollider = GetComponent<Collider2D>();
        m_spriteRenderer = GetComponent<SpriteRenderer>();

        _gameSession = GameObject.FindGameObjectWithTag(StaticDataManager.GAME_SESSION_TAG).GetComponent<GameSession>();
        
        _playerProxier = GameObject.FindGameObjectWithTag(StaticDataManager.PLAYER_PROXIER_TAG).GetComponent<PlayerProxier>();

        deathEvent += _gameSession.EntityDeath;
    }

    public override void DealDamage(int damage)
    {
        base.DealDamage(damage);
        
        damageDrawer.DrawDamagedNumber(-damage);
    }

    public PlayerProxier GetPlayerProxier()
    {
        if (_playerProxier == null)
        {
            foreach (var go in GameObject.FindGameObjectsWithTag(StaticDataManager.PLAYER_PROXIER_TAG))
            {
                _playerProxier = go.GetComponent<PlayerProxier>();

                if (_playerProxier)
                {
                    break;
                }
            }
        }
        
        return _playerProxier;
    }
    
    private void Start()
    {
        Debug.Log("<Color=#0000ff>战斗实体初始</Color>");
        GetPlayerProxier().SetBaseEntity(this);
        GetPlayerProxier().Initial();
        
        InitialMovement();
        GetCurrentTile();

        _gameSession.InitialHpBar(_hpBar);

        FlushStatus();
        _gameSession.AddEntity(EntityType.Player);
    }
    
    
    // Update is called once per frame
    private void Update()
    {
        switch (_status)
        {
            case EntityStatusEnum.Initialize:
                ExecuteBuffQueue(true);
                CheckCoverState();
                
                break;
            case EntityStatusEnum.Idle:
                ExecuteBuffQueue(true);
                
                break;
            case EntityStatusEnum.TurnStart:
                ExecuteBuffQueue(true);
                
                TurnStart();
                CheckCoverState();

                break;
            case EntityStatusEnum.TurnEnd:
                ExecuteBuffQueue(true);
                
                attackStep = 0;
                
                
                break;
            case EntityStatusEnum.Thinking:
                Thinking();
                break;
            case EntityStatusEnum.Moving:
                Moving();
                break;
            case EntityStatusEnum.Beaten:
                // TODO 往被射击方向转向
                ExecuteBuffQueue(true);
                beater = null;
                
                FlushStatus();
                
                if (is_need_play_next_animation)
                {
                    animator.Play("Hit");
                }
                
                // till animation end 
                if (animator.GetCurrentAnimatorStateInfo(0).IsName("Hit") && 
                    animator.GetCurrentAnimatorStateInfo(0).normalizedTime >= 1f)
                {
                    animator.Play("Idle");
                    _status = EntityStatusEnum.Thinking;                    
                }
                
                GetPlayerProxier().FlushAllUI();
                break;
            case EntityStatusEnum.Attack:
                // TODO 判断要执行近战还是远程的
                ExecuteBuffQueue(true);
                GetPlayerProxier().FlushAllUI();
                
                if (is_need_play_next_animation)
                {
                    switch (next_animation_type)
                    {
                        case AttackType.Short:
                            animator.SetFloat(SlashOrShootAttack, 0f);
                            animator.SetFloat(SlashStep, attackStep);
                            break;
                        case AttackType.Long:
                            animator.SetFloat(SlashOrShootAttack, 1f);
                            animator.SetFloat(ShootStep, attackStep);
                            break;
                        default:
                            throw new ArgumentOutOfRangeException();
                    }

                    animator.Play("Attack");

                    is_need_play_next_animation = false;
                    
                    attackStep += 1;
                    attackStep %= 3;
                }
                
                // till animation end 
                if ((animator.GetCurrentAnimatorStateInfo(0).IsName("Attack") && 
                    animator.GetCurrentAnimatorStateInfo(0).normalizedTime >= 1f) ||
                    animator.GetCurrentAnimatorStateInfo(0).IsName("Idle"))
                {
                    animator.Play("Idle");
                    _status = EntityStatusEnum.Thinking;                    
                }
                
                GetPlayerProxier().FlushAllUI();
                
                break;
            case EntityStatusEnum.Guard:
                ExecuteBuffQueue(true);
                break;
            case EntityStatusEnum.OverWatching:
                ExecuteBuffQueue(true);
                
                break;
            case EntityStatusEnum.Destroy:
                ExecuteBuffQueue(true);
                
                OnDeath();
                
                break;
            default:
                throw new ArgumentOutOfRangeException();
        }
    }

    public void OnDeath()
    {
        Death();
    }

    public void Death()
    {
        deathEvent?.Invoke(EntityType.Player);
    }
    
    public void Thinking()
    {
        // TODO 检查鼠标点击
        CheckMouse();
    }

    protected override void TurnStart()
    {
        _ap = _ap_max;
        _mp = _mp_max;
        _fp = _fp_max;
        
        // TODO 这个时候是由玩家决定思考接下来的行动
        // 不应该干涉 
        // 需要出现的内容有
        // TODO 显示移动格子
        if (!isSelectableTileDisplayed)
        {
            FindSelectableTiles();
            isSelectableTileDisplayed = true;
        }
        
        TileManager.ShowSelectableTiles();
        
        // TODO 显示卡牌内容
        if (!isPlayerDeckDisplayed)
        {
            GetPlayerProxier().DisplayPlayerCards();
            isPlayerDeckDisplayed = true;
        }
        
        _status = EntityStatusEnum.Thinking;
    }

    public override void TurnEnd()
    {
        isPlayerDeckDisplayed = false;
        isSelectableTileDisplayed = false; 
        isMoved = false; 
        
        GetPlayerProxier().TurnEnd();
    }

    public override void APChange(int changeVal)
    {
        base.APChange(changeVal);
        GetPlayerProxier()?.APNumListener?.Invoke(_ap);
    }
    
    public override void FPChange(int changeVal)
    {
        base.FPChange(changeVal);
        GetPlayerProxier()?.FPNumListener?.Invoke(_ap);
    }

    public void Moving()
    {
        Move();
        
        if (isMoving)
        {
            if (heading.x < 0 != m_is_facingLeft)
            {
                m_is_facingLeft = heading.x < 0;
                FlipSpriteX();
            }
            
            animator.Play("Move");
        }
        else
        {
            if (!isMoved) return;
            
            _status = EntityStatusEnum.Thinking;
            animator.Play("Idle");
            CheckCoverState();
            TileManager.HideAllTileOverlay();
        }
    }
    
    private void CheckMouse()
    {
//        if (EventSystem.current.IsPointerOverGameObject() || GetPlayerProxier().isHoldingCard)
        if (GetPlayerProxier().isHoldingCard)
        {
            return;
        }

        if (Input.GetButtonDown("Fire1"))
        {
            if (Camera.main != null)
            {
                // Extra 清除Tile颜色

                Vector2 clickPoint = Camera.main.ScreenToWorldPoint(Input.mousePosition);

                GameObject target = TileHelper.GetTileByPosition(clickPoint);
                if (target)
                {
                    TileMonoBehaviour t = target.GetComponent<TileMonoBehaviour>();

                    if (t.isSelectable)
                    {
                        MoveToTile(t);
                    }
                    isMoved = true;
                    _status = EntityStatusEnum.Moving;
                }
                
                TileManager.ShowMoveTiles();
            }
        }
    }

    private void SetBattleState(bool isBattle)
    {
        animator.SetFloat(Battle, isBattle ? 1 : 0);
    }
    
    private void CheckCoverState()
    {
        SetCoverState(IsInCover());
    }

    private bool IsInCover()
    {
        return TileManager.GetRangeCollider2Ds(gameObject.transform.position, 1f, AttackRangeType.Circle, StaticDataManager.BLOCK_LAYER)
                   .Length > 0;
    }

    private void SetCoverState(bool isCover)
    {
        animator.SetFloat(Cover, isCover ? 1 : 0);
    }

    private void OnDrawGizmos()
    {
        Gizmos.color = Color.cyan;
        Gizmos.DrawWireCube(transform.position, new Vector3(move * 2f + 1f, move * 2f + 1f));
    }
    
}
